import axios from "axios";
import type {
  AxiosRequestConfig,
  InternalAxiosRequestConfig,
  Canceler,
} from "axios";
import router from "../router";
import { Local } from '../utils/storage'
import { refreshToken } from "../api/common";
import { ElLoading, ElMessage } from "element-plus";
import type { LoadingOptions } from "element-plus";
import type { LoadingInstance } from "element-plus/es/components/loading/src/loading";
import { useUserInfo } from "../stores/userInfo";

/** @name 自定义配置 **/
interface CustomOptions {
  /** @name 是否开启loading层效果，默认为false **/
  loading: boolean;
  /** @name 是否开启取消重复请求，默认为 true **/
  repeat_request_cancel: boolean;
  /** @name 是否开启简洁的数据结构响应，默认为true **/
  reduct_data_format: boolean;
  /** @name 是否开启接口错误信息展示，默认为true **/
  error_message_show: boolean;
  /** @name 是否开启code不为0时的信息提示，默认为false **/
  code_message_show: boolean;
}

const pendingMap: Map<string, Canceler> = new Map();

/** @name 记录loading单实例 **/
const loadingInstance: {
  _target: LoadingInstance | null;
  _count: number;
} = {
  _target: null,
  _count: 0,
};
const userInfo = useUserInfo();
/**
 * @name 基于axios的二次封装
 * @param { AxiosRequestConfig } axiosConfig axios配置
 * @param { Partial<CustomOptions>?= } customOptions 自定义配置
 * @param { LoadingOptions?= } loadingOptions element-plus的loading配置
 */
function myAxios(
  axiosConfig: AxiosRequestConfig,
  customOptions?: Partial<CustomOptions>,
  loadingOptions?: LoadingOptions
) {
  const service = axios.create({
    baseURL: import.meta.env.VITE_BASE_API, // 设置统一的请求前缀
    timeout: 10000, // 设置统一的超时时长
    headers: {
      "think-lang": "",
      server: true,
    },
    responseType: "json",
  });

  // 自定义配置
  let custom_options: CustomOptions = Object.assign(
    {
      loading: false,
      repeat_request_cancel: true,
      reduct_data_format: true,
      error_message_show: true,
      code_message_show: false,
    },
    customOptions
  );

  // 请求拦截
  service.interceptors.request.use(
    (config) => {
      removePending(config);
      custom_options.repeat_request_cancel && addPending(config);
      if (custom_options.loading) {
        loadingInstance._count++;
        if (loadingInstance._count === 1) {
          loadingInstance._target = ElLoading.service(loadingOptions);
        }
      }
      // 自动携带token
      if (config.headers) {
        const userToken = userInfo.getToken();
        if (userToken) config.headers["token"] = userToken;
      }

      // if (getTokenAUTH() && typeof window !== "undefined") {
      //   config.headers.Authorization = getTokenAUTH();
      // }
      return config;
    },
    (error) => {
      return Promise.reject(error);
    }
  );
  // 响应拦截
  service.interceptors.response.use(
    (response) => {
      removePending(response.config);
      custom_options.loading && closeLoading(custom_options);
      if (response.data && response.data.code !== 1) {
        if (response.data.code == 409) {
          return refreshToken()
            .then((res) => {
              console.log(res)
              if (res.data.type == "user-refresh") {
                userInfo.setToken(res.data.token, "auth");
                response.headers["token"] = `${res.data.token}`;
              }
              return service(response.config);
            })
        }
        if (custom_options.code_message_show) {
          ElMessage({
            type: "error",
            message: response.data.message,
          });
        }
        // 自动跳转到路由name或path，仅限server端返回302的情况
        if (response.data.code == 302) {
          userInfo.removeToken()
          Local.remove('userInfo')
          if (response.data.data.routeName) {
            router.push({ name: response.data.data.routeName });
          } else if (response.data.data.routePath) {
            router.push({ path: response.data.data.routePath });
          }
        }
        return Promise.reject(response.data);
      } else if (
        custom_options.code_message_show &&
        response.data &&
        response.data.code == 1
      ) {
        ElMessage({
          message: response.data.msg ? response.data.msg : "successful",
          type: "success",
        });
      }
      return custom_options.reduct_data_format ? response.data : response;
    },
    (error) => {
      error.config && removePending(error.config);
      custom_options.loading && closeLoading(custom_options);
      custom_options.error_message_show && httpErrorStatusHandle(error);
      return Promise.reject(error);
    }
  );
  return service(axiosConfig);
}

/** @name 关闭loading **/
function closeLoading(_options: CustomOptions) {
  if (_options.loading && loadingInstance._count > 0) loadingInstance._count--;
  if (loadingInstance._count === 0 && loadingInstance._target) {
    loadingInstance._target.close();
    loadingInstance._target = null;
  }
}

/** @name 记录接口 **/
function addPending(config: InternalAxiosRequestConfig<any>) {
  const pendingKey = getPendingKey(config);
  config.cancelToken =
    config.cancelToken ||
    new axios.CancelToken((cancel) => {
      if (!pendingMap.has(pendingKey)) {
        pendingMap.set(pendingKey, cancel);
      }
    });
}

/** @name 移除接口 **/
function removePending(config: InternalAxiosRequestConfig<any>) {
  const pendingKey = getPendingKey(config);
  if (pendingMap.has(pendingKey)) {
    const cancel = pendingMap.get(pendingKey);
    cancel && cancel(pendingKey);
    pendingMap.delete(pendingKey);
  }
}

/** @name 通过接口请求信息生成唯一的key **/
function getPendingKey(config: InternalAxiosRequestConfig<any>) {
  let { url, method, params, data } = config;
  if (typeof data === "string") data = JSON.parse(data);
  return [url, method, JSON.stringify(params), JSON.stringify(data)].join("&");
}

/** @name 接口异常时，预订制message **/
function httpErrorStatusHandle(error: any) {
  if (axios.isCancel(error))
    return console.error("请求的重复请求：" + error.message);
  let messageString = "";
  if (error && error.response) {
    switch (error.response.status) {
      case 302:
        messageString = "接口重定向了！";
        break;
      case 400:
        messageString = "参数不正确！";
        break;
      case 401:
        messageString = "您未登录，或者登录已经超时，请先登录！";
        break;
      case 403:
        messageString = "您没有权限操作！";
        break;
      case 404:
        messageString = `请求地址出错: ${error.response.config.url}`;
        break;
      case 408:
        messageString = "请求超时！";
        break;
      case 409:
        messageString = "系统已存在相同数据！";
        break;
      case 500:
        messageString = "服务器内部错误！";
        break;
      case 501:
        messageString = "服务未实现！";
        break;
      case 502:
        messageString = "网关错误！";
        break;
      case 503:
        messageString = "服务不可用！";
        break;
      case 504:
        messageString = "服务暂时无法访问，请稍后再试！";
        break;
      case 505:
        messageString = "HTTP版本不受支持！";
        break;
      default:
        messageString = "异常问题，请联系管理员！";
        break;
    }
  }
  if (error.message.includes("timeout")) messageString = "网络请求超时！";
  if (error.message.includes("Network"))
    messageString = window.navigator.onLine ? "服务端异常！" : "您断网了！";
  ElMessage({
    type: "error",
    message: messageString,
  });
}

export default myAxios;
